#include "StdAfx.h"
#include "FnMeshRenderer.h"
#include <gl/glut.h>
#include <PosGraph/Modeling/Object.h>


FnMeshRenderer::FnMeshRenderer(Mesh& _mesh)
: mesh_(_mesh)
{
	draw_type_ = kFlatShadedHiddenLine;
	mesh().request_vertex_normals();
	mesh().request_face_normals();
}

FnMeshRenderer::~FnMeshRenderer(void)
{
	mesh().release_vertex_normals();
	mesh().release_face_normals();
}

void FnMeshRenderer::calc_normals()
{
	Mesh::VertexIter v_it;
	Mesh::FaceIter f_it;

	for(f_it = mesh().faces_begin(); f_it != mesh().faces_end(); ++f_it){
		mesh().set_normal(f_it, mesh().calc_face_normal(f_it));
	}

	for(v_it = mesh().vertices_begin(); v_it != mesh().vertices_end(); ++v_it)
	{
		mesh().set_normal(v_it, mesh().calc_vertex_normal(v_it));
	}
}

void FnMeshRenderer::draw_mesh()
{
	Mesh::EdgeIter e_it;
	Mesh::FaceIter f_it;
	Mesh::Point pos;

	if(draw_type_ == kFlatShadedHiddenLine || draw_type_ == kSmoothShadedHiddenLine){
		glEnable(GL_POLYGON_OFFSET_FILL);
		glPolygonOffset(1.0, 1.0);
	}
	if(draw_type_ == kFlatShadedHiddenLine || draw_type_ == kFlatShaded){

		for(f_it = mesh().faces_begin(); f_it != mesh().faces_end(); ++f_it){
			//if(valence(f_it) > 3 ){
			if(fprop_cube_face_.is_valid()){
				if(mesh().property(fprop_cube_face_, f_it) == kNY)
					glColor3f(0.0, 0.0, 1.0);
				else if (mesh().property(fprop_cube_face_, f_it) == kPY)
					glColor3f(1.0, 0.0, 0.0);
				//else if(mesh().property(fprop_cube_face_, f_it) == kPX0)
				//	glColor3f(0.0, 1.0, 0.0);
				//else if(mesh().property(fprop_cube_face_, f_it) == kNX0)
				//	glColor3f(0.0, 1.0, 1.0);
				//else if(mesh().property(fprop_cube_face_, f_it) == kPZ0)
				//	glColor3f(1.0, 1.0, 0.0);
				//else if(mesh().property(fprop_cube_face_, f_it) == kNZ0)
				//	glColor3f(1.0, 0.0, 1.0);
				//else if(mesh().property(fprop_cube_face_, f_it) == kPX1)
				//	glColor3f(0.0, 0.5, 0.0);
				//else if(mesh().property(fprop_cube_face_, f_it) == kNX1)
				//	glColor3f(0.0, 0.5, 0.5);
				//else if(mesh().property(fprop_cube_face_, f_it) == kPZ1)
				//	glColor3f(0.5, 0.5, 0.0);
				//else if(mesh().property(fprop_cube_face_, f_it) == kNZ1)
				//	glColor3f(0.5, 0.0, 0.5);
				else if(mesh().property(fprop_cube_face_, f_it) == kNone)
					glColor3f(1.0, 1.0, 1.0);
				else if(mesh().property(fprop_cube_face_, f_it) >= 2)	//side faces
				{
					int level = (mesh().property(fprop_cube_face_, f_it) - 2) / 4 + 1;
					int side = (mesh().property(fprop_cube_face_, f_it) - 2) % 4;
					float bright = level/((nSides - 2)/4.f);
					switch (side)
					{
					case 0:		//kPZ
						glColor3f(bright*1.0, bright*1.0, 0.0);
						break;
					case 1:		//kPX
						glColor3f(0.0, bright*1.0, 0.0);
						break;
					case 2:		//kNZ
						glColor3f(bright*1.0, 0.0,bright*1.0);
						break;
					case 3:		//kNX
						glColor3f(0.0, bright*1.0, bright*1.0);
						break;
					}
				}
				else
					glColor3f(0.5, 0.5, 0.5);
			}
			else{
				glColor3f(1.0, 1.0, 1.0);
				//continue;
			}

			glBegin(GL_POLYGON);
			for(Mesh::FaceVertexIter fv_it = mesh().fv_iter(f_it); fv_it; ++fv_it){
				Mesh::Point pos = mesh().point(fv_it);
				glVertex3f(pos[0], pos[1], pos[2]);
			}
			glEnd();
		}

	}
	if(draw_type_ == kSmoothShaded || draw_type_ == kSmoothShadedHiddenLine){
		for(f_it = mesh().faces_begin(); f_it != mesh().faces_end(); ++f_it){
			//if(valence(f_it) > 3 ){
			glBegin(GL_POLYGON);
			for(Mesh::FaceVertexIter fv_it = mesh().fv_iter(f_it); fv_it; ++fv_it){
				if(vprop_cube_face_.is_valid()){
					if(mesh().property(vprop_cube_face_, fv_it) == kNY)
						glColor3f(0.0, 0.0, 1.0);
					else if (mesh().property(vprop_cube_face_, fv_it) == kPY)
						glColor3f(1.0, 0.0, 0.0);
					else if(mesh().property(fprop_cube_face_, f_it) >= 2)	//side faces
					{
						int level = (mesh().property(fprop_cube_face_, f_it) - 2) / 4 + 1;
						int side = (mesh().property(fprop_cube_face_, f_it) - 2) % 4;
						float bright = level/((nSides - 2)/4.f);
						switch (side)
						{
						case 0:		//kPZ
							glColor3f(bright*1.0, bright*1.0, 0.0);
							break;
						case 1:		//kPX
							glColor3f(0.0, bright*1.0, 0.0);
							break;
						case 2:		//kNZ
							glColor3f(bright*1.0, 0.0,bright*1.0);
							break;
						case 3:		//kNX
							glColor3f(0.0, bright*1.0, bright*1.0);
							break;
						}
					}
					else
						glColor3f(1.0, 1.0, 1.0);
				}
				else{
					glColor3f(1.0, 1.0, 1.0);
					//continue;
				}

				Mesh::Point pos = mesh().point(fv_it);
				glVertex3f(pos[0], pos[1], pos[2]);
			}
			glEnd();
		}

	}
	if(draw_type_ == kFlatShadedHiddenLine || draw_type_ == kSmoothShadedHiddenLine)
		glDisable(GL_POLYGON_OFFSET_FILL);

	if(draw_type_ == kWireframe || draw_type_ == kFlatShadedHiddenLine || draw_type_ == kSmoothShadedHiddenLine){


		if(eprop_type_.is_valid())
			glLineWidth(3.0);
		else
			glLineWidth(1.0);

		glBegin(GL_LINES);
		for(e_it = mesh().edges_begin(); e_it != mesh().edges_end(); ++e_it){
			if(!eprop_type_.is_valid() || mesh().property(eprop_type_, e_it) == kWedgeEdge){
				glColor3f(0.0, 0.0, 0.0);

				pos = mesh().point(mesh().to_vertex_handle(mesh().halfedge_handle(e_it, 0)));
				glVertex3f(pos[0], pos[1], pos[2]);
				pos = mesh().point(mesh().to_vertex_handle(mesh().halfedge_handle(e_it, 1)));
				glVertex3f(pos[0], pos[1], pos[2]);
			}
		}
		glEnd();

		glLineWidth(1.0);

		glBegin(GL_LINES);
		for(e_it = mesh().edges_begin(); e_it != mesh().edges_end(); ++e_it){
			if(!eprop_type_.is_valid() || mesh().property(eprop_type_, e_it) == kWedgeEdge){
				continue;
			}

			Mesh::Normal n = (mesh().normal(mesh().from_vertex_handle(mesh().halfedge_handle(e_it, 0))) + mesh().normal(mesh().from_vertex_handle(mesh().halfedge_handle(e_it, 1))));
			Mesh::Point p  = (mesh().point(mesh().from_vertex_handle(mesh().halfedge_handle(e_it, 0))) + mesh().point(mesh().from_vertex_handle(mesh().halfedge_handle(e_it, 1))))*0.5;

			p[2] = p[2] - 100.0;

			n = n/n.length();
			p = p/p.length();

			float factor = OpenMesh::dot(n, -p);

			factor = fabs(factor)*0.5+0.5;

			Mesh::FaceHandle fh = mesh().face_handle(mesh().halfedge_handle(e_it, 0));
			//glNormal3f(n[0], n[1], n[2]);

			float col[3];

			if(mesh().property(fprop_cube_face_, fh) == kNY)
				col[0] = 0.8, col[1] = 0.8, col[2] = 1.0;
			else if (mesh().property(fprop_cube_face_, fh) == kPY)
				col[0] = 1.0, col[1] = 0.8, col[2] = 0.8;
			//else if(mesh().property(fprop_cube_face_, fh) == kPX0)
			//	col[0] = 0.8, col[1] = 1.0, col[2] = 0.8;
			//else if(mesh().property(fprop_cube_face_, fh) == kNX0)
			//	col[0] = 0.8, col[1] = 1.0, col[2] = 1.0;
			//else if(mesh().property(fprop_cube_face_, fh) == kPZ0)
			//	col[0] = 1.0, col[1] = 1.0, col[2] = 0.8;
			//else if(mesh().property(fprop_cube_face_, fh) == kNZ0)
			//	col[0] = 1.0, col[1] = 0.8, col[2] = 1.0;
			//else if(mesh().property(fprop_cube_face_, fh) == kPX1)
			//	col[0] = 0.4, col[1] = 1.0, col[2] = 0.4;
			//else if(mesh().property(fprop_cube_face_, fh) == kNX1)
			//	col[0] = 0.4, col[1] = 1.0, col[2] = 1.0;
			//else if(mesh().property(fprop_cube_face_, fh) == kPZ1)
			//	col[0] = 1.0, col[1] = 1.0, col[2] = 0.4;
			//else if(mesh().property(fprop_cube_face_, fh) == kNZ1)
			//	col[0] = 1.0, col[1] = 0.4, col[2] = 1.0;
			else if(mesh().property(fprop_cube_face_, fh) == kNone)
				col[0] = 1.0, col[1] = 1.0, col[2] = 1.0;		
			else if(mesh().property(fprop_cube_face_, fh) >= 2)	//side faces
			{
				int level = (mesh().property(fprop_cube_face_, fh) - 2) / 4 + 1;
				int side = (mesh().property(fprop_cube_face_, fh) - 2) % 4;
				float bright = level/((nSides - 2)/4.f);
				switch (side)
				{
				case 0:		//kPZ
					col[0] = bright*1.0, col[1] = bright*1.0, col[2] = bright*0.8;
					break;
				case 1:		//kPX
					col[0] = bright*0.8, col[1] = bright*1.0, col[2] = bright*0.8;
					break;
				case 2:		//kNZ
					col[0] = bright*1.0, col[1] = bright*0.8, col[2] = bright*1.0;
					break;
				case 3:		//kNX
					col[0] = bright*0.8, col[1] = bright*1.0, col[2] = bright*1.0;
					break;
				}
			}
			else
				col[0] = 0.5, col[1] = 0.5, col[2] = 0.5;

			col[0] *= factor;
			col[1] *= factor;
			col[2] *= factor;

			glColor3f(col[0], col[1], col[2]);

			pos = mesh().point(mesh().to_vertex_handle(mesh().halfedge_handle(e_it, 0)));
			glVertex3f(pos[0], pos[1], pos[2]);
			pos = mesh().point(mesh().to_vertex_handle(mesh().halfedge_handle(e_it, 1)));
			glVertex3f(pos[0], pos[1], pos[2]);

		}
		glEnd();


	}


	if(!vprop_cube_face_.is_valid())
		return;

	/*Mesh::VertexIter v_it;

	glPointSize(4);
	for(v_it = mesh().vertices_begin(); v_it != mesh().vertices_end(); ++v_it)
	{
	//if(valence(f_it) > 3 ){
	if(mesh().property(vprop_cube_face_, v_it) == kNY){
	glColor3f(0.0, 0.0, 1.0);
	}
	else if(mesh().property(vprop_cube_face_, v_it) == kPY){
	glColor3f(1.0, 0.0, 0.0);
	}
	else if(mesh().property(vprop_cube_face_, v_it) == kPX){
	glColor3f(0.0, 1.0, 0.0);
	}
	else if(mesh().property(vprop_cube_face_, v_it) == kNX){
	glColor3f(0.0, 1.0, 1.0);
	}
	else if(mesh().property(vprop_cube_face_, v_it) == kPZ){
	glColor3f(1.0, 1.0, 0.0);
	}
	else if(mesh().property(vprop_cube_face_, v_it) == kNZ){
	glColor3f(1.0, 0.0, 1.0);
	}
	else{
	glColor3f(0.7, 0.7, 0.7);
	//continue;

	Mesh::Point pos = mesh().point(v_it);
	glPushMatrix();
	glTranslatef(pos[0], pos[1], pos[2]);
	glutSolidCube(0.01);
	glPopMatrix();
	}

	Mesh::Point pos = mesh().point(v_it);
	glBegin(GL_POINTS);
	glVertex3f(pos[0], pos[1], pos[2]);
	glEnd();	
	}*/

}

void FnMeshRenderer::draw_names(const std::string &_primitive)
{
  if (_primitive == "Vertex")
  {
    draw_vertex_names();
  }
  else if (_primitive == "Edge")
  {
    
  }
  else if (_primitive == "Face")
  {
    
  }
  else if (_primitive == "Halfedge")
  {
    
  }
}

void FnMeshRenderer::draw_vertex_names()
{
  Mesh::VertexIter      v_it;
  Mesh::VertexHandle    vh;
  Mesh::Point pos;

  glPushName((GLuint) this);
  glPushName((GLuint) PosGraph::Modeling::kVertex);
  
  for (v_it=mesh().vertices_begin(); v_it!=mesh().vertices_end(); ++v_it)
  {
    vh = v_it;

	pos = mesh().point(vh);

    glPushName(vh.idx());
    glBegin(GL_POINTS);
    glVertex3f(pos[0], pos[1], pos[2]);
    glEnd();
    glPopName();
  }

  glPopName();
}